package load

import (
	"encoding/json"
	"fmt"
	"game/game-design-v.xnanz/meta"
	"reflect"
	"strconv"
	"unsafe"
)

var Caches map[reflect.Type]IDesignCache

func init() {
	Caches = make(map[reflect.Type]IDesignCache)
}

func Register(designCache IDesignCache) {
	Caches[reflect.TypeOf(designCache)] = designCache
}

type IDesignData interface {
	Id() int
}

type IDictionaryData interface {
	GetKey() string
	GetValue() string
}

type IDesignCache interface {
	StructObj() interface{}
	FileName() string
	Load(designMeta meta.DesignClassMeta, thisCache IDesignCache)
	LoadIndex()
}

type DesignCache struct {
	KeyValues  map[int]interface{}
	Datas      []interface{}
	Dictionary map[string]string
}

func (d *DesignCache) Load(designMeta meta.DesignClassMeta, thisCache IDesignCache) {
	d.KeyValues = make(map[int]interface{})
	d.formStruct(designMeta, thisCache)
	thisCache.LoadIndex()
	// if designMeta.HasDictionary() {
	// 	d.loadDictionary()
	// 	//TODO 设置字典的值
	// }
	d.formDictionary(thisCache)
}

func (d *DesignCache) LoadIndex() {
	fmt.Println("DesignCache LoadIndex")
}
func (d *DesignCache) loadDictionary() {
	dictionary := make(map[string]string)
	for _, v := range d.Datas {
		vPtr := v.(IDictionaryData)
		dictionary[vPtr.GetKey()] = vPtr.GetValue()
	}
	d.Dictionary = dictionary
}

func (d *DesignCache) formDictionary(thisCache IDesignCache) {
	rValue := reflect.ValueOf(thisCache)
	rType := reflect.TypeOf(rValue.Elem().Interface())

	for i := 0; i < rType.NumField(); i++ {
		structField := rType.Field(i)
		structTag := structField.Tag
		if structTag.Get("dictionary") == "" {
			continue
		}
		objField := rValue.Elem().Field(i)
		dictionaryValue := d.Dictionary[structTag.Get("dictionary")]

		setFieldValue(structField.Type.Kind(), dictionaryValue, objField)
	}
}

func (d *DesignCache) formStruct(designMeta meta.DesignClassMeta, designCache IDesignCache) {
	// rValue := reflect.ValueOf(designCache.StructObj())
	// rType := rValue.Type()

	// for _, row := range designMeta.GetDatas() {
	// 	d.formObject(rType, designMeta, row)
	// }
}

func (d *DesignCache) formObject(rType reflect.Type, designMeta meta.DesignClassMeta, row []string) {
	// //创建对象
	// objPtrValue := reflect.New(rType)
	// //结构体的字段数量
	// numFile := rType.NumField()
	// for i := 0; i < numFile; i++ {
	// 	field := rType.Field(i)

	// 	fieldName := field.Name

	// 	columnIndex, exist := designMeta.GetColumnIndex(fieldName)
	// 	if !exist {
	// 		fmt.Println("表中没有字段", fieldName)
	// 		continue
	// 	}

	// 	fieldValue := reflect.ValueOf(row[columnIndex])
	// 	fieldKind := field.Type.Kind()
	// 	//对象上的字段对象
	// 	objField := objPtrValue.Elem().FieldByName(fieldName) //TODO
	// 	//设置值到字段中
	// 	setFieldValue(fieldKind, fieldValue.String(), objField)
	// }
	// objTemp := objPtrValue.Interface()
	// d.Datas = append(d.Datas, objTemp)
	// d.KeyValues[objTemp.(IDesignData).Id()] = objTemp
}

func setFieldValue(fieldKind reflect.Kind, fieldValue string, objField reflect.Value) {
	if fieldKind == reflect.Int || fieldKind == reflect.Int64 {
		int64Value, err := strconv.ParseInt(fieldValue, 10, 64)
		intValue0 := int(int64Value)

		intValue := reflect.ValueOf(intValue0)

		if err == nil {
			setValue(objField, intValue)
		} else {
			fmt.Println(err)
		}
	} else if fieldKind == reflect.String {
		strValue := reflect.ValueOf(fieldValue)

		setValue(objField, strValue)
	} else if fieldKind == reflect.Struct || fieldKind == reflect.Slice || fieldKind == reflect.Map {
		//结构体、切片（列表）、Map的数据都是json格式，将三者暂时统称为对象
		//对象的Value包装指针
		jsonValue := reflect.New(objField.Type())
		//对象的实体
		jsonObj := jsonValue.Interface()
		err := json.Unmarshal([]byte(fieldValue), &jsonObj)
		//把对象的Value包装指针里面的实体Elem取出去
		jsonValue = jsonValue.Elem()
		if err == nil {
			setValue(objField, jsonValue)
		} else {
			fmt.Println(err)
		}
	} else {
		fmt.Println("这是什么类别的字段？", fieldKind)
	} //TODO 这里可以扩展各种类型的设值
}

func setValue(objField reflect.Value, objValue reflect.Value) {
	if objField.CanSet() {
		objField.Set(objValue)
	} else {
		objField = reflect.NewAt(objField.Type(), unsafe.Pointer(objField.UnsafeAddr())).Elem()
		objField.Set(objValue)
	}
}
